package com.lt.test.provider.service;

import com.lt.test.api.RedisService;
import com.lt.test.common.util.SerializeUtil;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Set;

@Service("redisService")
public class RedisServiceImpl implements RedisService {
	@Resource
	private RedisTemplate<Serializable, Serializable> redisTemplate;
	
	@Override
	public String set(final byte[] key, final byte[] value, final Long seconds) {
		if(key == null || value == null || key.length == 0 || value.length == 0){
			return "key和value不能为空，长度不能为0";
		}
		return redisTemplate.execute(new RedisCallback<String>() {
			@Override
			public String doInRedis(RedisConnection connection) {
				try {
					connection.set(key, value);
					if (seconds != null) {
						connection.expire(key, seconds);
					}
					return "Ok";
				} catch (DataAccessException e) {
					return "Failure : DataAccessException";
				} finally {
					connection.close();
				}
			}
		});
	}

	@Override
	public String set(final String key, final Object value, final Long seconds) {
		if(key == null || value == null){
			return "key和value不能为空";
		}
		final byte[] sKey =  redisTemplate.getStringSerializer().serialize(key);
		final byte[] sValue = SerializeUtil.serialize(value);
		return this.set(sKey, sValue, seconds);
	}

	@Override
	public Object get(final String key) {
		if(key == null || key.equals("")){
			return null;
		}
		return redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection connection) {
				final byte[] sKey =  redisTemplate.getStringSerializer().serialize(key);
				try {
					if(!connection.exists(sKey)) {
						return null;
					}
					byte[] value = connection.get(sKey);
					return SerializeUtil.unserialize(value);
				} catch (DataAccessException e) {
					return null;
				} finally {
					connection.close();
				}
			}
		});
	}

	@Override
	public boolean del(final String key) {
		if(key == null || key.equals("")){
			return false;
		}
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) {
				try {
					final byte[] keys = redisTemplate.getStringSerializer().serialize(key);
					connection.del(keys);
					return true;
				} catch (DataAccessException e) {
					return false;
				} finally {
					connection.close();
				}
			}
			
		});
	}

	@Override
	public boolean flushDb() {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) {
				try {
					connection.flushDb();
					return true;
				} catch (DataAccessException e) {
					return false;
				} finally {
					connection.close();
				}
			}
		});
	}

	@Override
	public boolean exists(final String key) {
		if(key == null || key.equals("")){
			return false;
		}
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) {
				try {
					final byte[] keys = redisTemplate.getStringSerializer().serialize(key);
					return connection.exists(keys);
				} catch (DataAccessException e) {
					return false;
				} finally {
					connection.close();
				}
			}
		});
	}
	
	public Set<byte[]> keys(final String pattern) {
		if(pattern == null || pattern.equals("")){
			return null;
		}
		return redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
			@Override
			public Set<byte[]> doInRedis(RedisConnection connection) {
				try {
					return connection.keys(pattern.getBytes());
				} catch (DataAccessException e) {
					return null;
				} finally {
					connection.close();
				}
			}
		});
	}
	
	public boolean remove(Set<byte[]> bytes){
		if(bytes == null || bytes.isEmpty()){
			return false;
		}
		final byte[][] bbs = new byte[bytes.size()][];
		bytes.toArray(bbs);
	
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) {
				try {
					connection.del(bbs);
					return true;
				} catch (DataAccessException e) {
					return false;
				} finally {
					connection.close();
				}
			}
		});
	}
}
